package com.koomii.common.util.bean;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;

public class DataMergeUtils {
	public final static Logger log = LogManager.getLogger(DataMergeUtils.class);
	
	/**
     * 主要用来避免1+n的查询。如在查询学生列表时，要得到学生的班主任信息。<br/>
     * 如果采用left join的方式，必然会导致从db到web传输数据量大。班主任被反复join过来。<br/>
     * 如果拿到学生列表后，再去一个个查询班主任信息。必然会导致1+n的查询<br/>
     * 这里的思想是：先查学生列表。然后再把学生信息中的班主任的id拼装成字符串。以in的方式查询(当然有更高效的方式)<br/>
     * 得到班主任列表后，再一个个塞回学生的list<br/>
     * <p/>
     * 从一个List中获取SQL in格式的字符串<br/>
     * <p/>
     * @param list 主数据列表，如学生列表
     * @param foreignFieldName 外部参考数据的字段，如：班主任Id
     * @return in sql like a,b,c
     * 
     */
    public static String sqlIn(List list, String foreignFieldName){
    	Set<String> values = new HashSet<String>(); //放的是查询到的集合的相关类的，使用Set过滤重复数据
    	//集合类
        for (Object o : list) {
            String property = null;
            try {
                property = BeanUtils.getProperty(o, foreignFieldName);
                if (!StringUtils.isEmpty(property)) {
                    values.add(property);
                }
            } catch (Exception e) {
                log.debug("getProperty error! " + foreignFieldName);
            }
        }
        //查询到的父不为空
        if (!values.isEmpty()) {
            StringBuilder builder = new StringBuilder();
            //拼装成字符串
            for (String value : values) {
                builder.append(',');
                builder.append(value);
            }
            return builder.substring(1);
        }
    	
    	return "";
    }
    
    /**
     * 主要用来避免1+n的查询。如在查询学生列表时，要得到学生的班主任信息。<br/>
     * 如果采用left join的方式，必然会导致从db到web传输数据量大。班主任被反复join过来。<br/>
     * 如果拿到学生列表后，再去一个个查询班主任信息。必然会导致1+n的查询<br/>
     * 这里的思想是：先查学生列表。然后再把学生信息中的班主任的id拼装成字符串。以in的方式查询(当然有更高效的方式)<br/>
     * 得到班主任列表后，再一个个塞回学生的list<br/>
     * <p/>
     * 合并两个List，将外部数据对象填充<br/>
     * <p/>
     * @param list 主数据列表，如学生列表
     * @param foreignFieldName 外部参考数据的字段，如：班主任Id
     * @param setFieldname 设置数据的字段，如班主任名称
     * @param merges 外部数据列表，如班主任列表
     * @param mergeFieldKeyName 外部数据字段，如班主任表中的班主任名称
     *
     */
    public static <E> void mergeList(List list, String foreignFieldName, String setFieldname, List<E> merges , String mergeKeyField) {
        try {
            for (Object obj : list) {
                String val = null;
                try {
                    val = BeanUtils.getProperty(obj, foreignFieldName);
                } catch (Exception e) {
                    log.debug("getProperty error! " + foreignFieldName);
                }
                //塞回去
                if (!StringUtils.isEmpty(val)) {
                	List<E> mergeList = new ArrayList<E>();
                    for (E merge : merges) {
                        if (val.equals(BeanUtils.getProperty(merge, mergeKeyField))) {
                        	mergeList.add(merge);
                        }
                    }
                    BeanUtils.setProperty(obj, setFieldname, mergeList);
                }
            }
        } catch (Exception e) {
            log.error("merge error!", e);
            throw new RuntimeException("merge error!", e);
        }
    }
    
    /**
     * 主要用来避免1+n的查询。如在查询学生列表时，要得到学生的班主任信息。<br/>
     * 如果采用left join的方式，必然会导致从db到web传输数据量大。班主任被反复join过来。<br/>
     * 如果拿到学生列表后，再去一个个查询班主任信息。必然会导致1+n的查询<br/>
     * 这里的思想是：先查学生列表。然后再把学生信息中的班主任的id拼装成字符串。以in的方式查询(当然有更高效的方式)<br/>
     * 得到班主任列表后，再一个个塞回学生的list<br/>
     * <p/>
     * 合并两个List，将外部数据对象填充<br/>
     * <p/>
     * @param list 主数据列表，如学生列表
     * @param foreignFieldName 外部参考数据的字段，如：班主任Id
     * @param setFieldname 设置数据的字段，如班主任名称
     * @param merges 外部数据列表，如班主任列表
     * @param mergeFieldKeyName 外部数据字段，如班主任表中的班主任名称
     *
     */
    public static void mergeObject(List list, String foreignFieldName, String setFieldname, List merges , String mergeKeyField) {
        try {
            for (Object obj : list) {
                String val = null;
                try {
                    val = BeanUtils.getProperty(obj, foreignFieldName);
                } catch (Exception e) {
                    log.debug("getProperty error! " + foreignFieldName);
                }
                //塞回去
                if (!StringUtils.isEmpty(val)) {
                    for (Object merge : merges) {
                        if (val.equals(BeanUtils.getProperty(merge, mergeKeyField))) {
                            BeanUtils.setProperty(obj, setFieldname, merge);
                            break;
                        }
                    }
                }
            }
        } catch (Exception e) {
            log.error("merge error!", e);
            throw new RuntimeException("merge error!", e);
        }
    }
    
    /**
     * 主要用来避免1+n的查询。如在查询学生列表时，要得到学生的班主任信息。<br/>
     * 如果采用left join的方式，必然会导致从db到web传输数据量大。班主任被反复join过来。<br/>
     * 如果拿到学生列表后，再去一个个查询班主任信息。必然会导致1+n的查询<br/>
     * 这里的思想是：先查学生列表。然后再把学生信息中的班主任的id拼装成字符串。以in的方式查询(当然有更高效的方式)<br/>
     * 得到班主任列表后，再一个个塞回学生的list<br/>
     * <p/>
     * 合并两个List，将外部数据填充属性<br/>
     * <p/>
     * @param list 主数据列表，如学生列表
     * @param foreignFieldName 外部参考数据的字段，如：班主任Id
     * @param setFieldname 设置数据的字段，如班主任名称
     * @param merges 外部数据列表，如班主任列表
     * @param mergeFieldKeyName 外部数据字段，如班主任表中的班主任名称
     *
     */
    public static void mergeProperty(List list, String foreignFieldName, String setFieldname, List merges , String mergeKeyField, String mergeValueField) {
        try {
            for (Object obj : list) {
                String val = null;
                try {
                    val = BeanUtils.getProperty(obj, foreignFieldName);
                } catch (Exception e) {
                    log.debug("getProperty error! " + foreignFieldName);
                }
                //塞回去
                if (!StringUtils.isEmpty(val)) {
                    for (Object merge : merges) {
                        if (val.equals(BeanUtils.getProperty(merge, mergeKeyField))) {
                            BeanUtils.setProperty(obj, setFieldname, BeanUtils.getProperty(merge, mergeValueField));
                            break;
                        }
                    }
                }
            }
        } catch (Exception e) {
            log.error("merge error!", e);
            throw new RuntimeException("merge error!", e);
        }
    }
}
